iT邦幫忙

2022 iThome 鐵人賽

DAY 28
0
自我挑戰組

從前端角度看30天學Python系列 第 28

【Day 28】Python with MongoDB

  • 分享至 

  • xImage
  •  
  • 安裝套件
  • 連線至MongoDB
  • 創造一個 database 和 collection
  • 新增資料
  • 查找資料
  • 限制查詢回傳數
  • 查詢回傳排序
  • 更新資料
  • 刪除資料
  • 刪除資料庫

這篇文章是閱讀Asabeneh的30 Days Of Python: Day 27 - Python with MongoDB後的學習筆記與心得。

這個章節會使用繼續使用 Day 27 的 Flask 框架並搭配一個很常見的 noSQL 資料庫選擇—MongoDB;noSQL 和 SQL 就我淺白的理解,就是一個是卡片式,另一個是表格式的管理資料。


申請帳號及起始環境的部分可以參考原文章,但順序有一點變動。或是比較近期的文章;因為有一點差異,像是現在是先新增使用者,然後才選擇雲端服務供應商及區域,這部份我選擇 AWS,區域選東京。

完成後會拿到一串連結用的字串:

mongodb+srv://username:<password>@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority

要把 <password> 的部份換成剛剛新增使用者時設置的密碼。

[!DANGER] 記得不要放到 Git 裡
因為密碼就在這個 link 裡,你不應該把這個資訊 commit 到 git 或甚至上傳到公開的 GitHub repo。

安裝套件

需要安裝 pymongo 以及 dnspython 這兩個套件

[!INFO] 參考 MongoDB 這個頁面說明
PyMongo 是同步處理,異步處理可以使用 Motor

pip install pymongo dnspython

連線至MongoDB

類似於 Day 27 的設置,起一個伺服器,但基本上今天不會用到網頁,看終端機 (terminal) 那邊的訊息就能確認結果:

from flask import Flask
import os
import pymongo

MONGODB_URI = "mongodb+srv://username:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority"

client = pymongo.MongoClient(MONGODB_URI)
print(client.list_database_names())

app = Flask(__name__)
if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app.run(debug=True, host="0.0.0.0", port=port)

這邊應該能看到終端有印出 ['admin', 'local'] 代表有連到 MongoDB。

創造一個 database 和 collection

這邊開始可以沿用上一個階段的程式碼,只要修改部份的命令就好,以下面例子來說:

from flask import Flask
import os
import pymongo

MONGODB_URI = "mongodb+srv://username:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority"

client = pymongo.MongoClient(MONGODB_URI)

# 連線到現有的資料庫,或創造一個
db = client["thirty_days_of_python"]

# 新增一個 collection - studuents 並加入一個項目
db.students.insert_one({"name": "Asabeneh", "country": "Finland", "city": "Helsinki", "age": 250})

print(client.list_database_names())

app = Flask(__name__)
if __name__ == "__main__":
    port = int(os.environ.get("PORT", 5000))
    app.run(debug=True, host="0.0.0.0", port=port)
  • db 這個變數在後面的例子會一直用到。
  • students 這個 db 的屬性就是 collection,可以在我們創建的 MongoDB 頁面,進入 30DaysOfPython 的專案,點選 collection 頁籤看到每次操作存入的資料狀況。
  • 另外可以從 client.list_database_names() 的回傳結果看到新增的 database:['thirty_days_of_python', 'admin', 'local']

新增資料

現在已經有了 students 這個 collection,想要新增新的項目進去,就如同前面創造一樣,使用 insert_one(item) 方法:

記得要先把前面的 insert_one 刪掉,不然會重複新增。

students = [
    {'name':'David','country':'UK','city':'London','age':34},
    {'name':'John','country':'Sweden','city':'Stockholm','age':28},
    {'name':'Sami','country':'Finland','city':'Helsinki','age':25},
]

for student in students:
    db.students.insert_one(student)
  • 可以到 MongoDB 的管理頁面確認結果。

查找資料

可以使用回傳第一筆資料的 find_one() 或是 回傳全部資料的 find()

first_student = db.students.find_one()
print(first_student)

students = db.students.find()
for student in students:
    print(student)

印出結果:

{'_id': ObjectId('634651ae7d83d79be86e9603'), 'name': 'Asabeneh', 'country': 'Finland', 
'city': 'Helsinki', 'age': 250}

--- 方便閱讀的分隔線(非實際印出) ---

{'_id': ObjectId('634651ae7d83d79be86e9603'), 'name': 'Asabeneh', 'country': 'Finland', 
'city': 'Helsinki', 'age': 250}
{'_id': ObjectId('63465741861a2ea6862cb7ef'), 'name': 'David', 'country': 'UK', 'city': 
'London', 'age': 34}
{'_id': ObjectId('63465741861a2ea6862cb7f0'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28}
{'_id': ObjectId('63465741861a2ea6862cb7f1'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}

另外 find(WHERE, SELECT) 可以接受兩個參數,第一個是要符合的條件,第二個是要回傳的欄位,就像 SQL 中的 WHERE 和 SELECT 的作用;可以兩個參數都給,但這邊為了方便演示各自都只給一個參數:

  • WHERE 這個參數可以使用 Operators (modifiers),像是 $gt (greater than)
# 0是不要,1是要,這邊只要 name 和 country 的欄位資料
students = db.students.find({}, {"_id": 0, "name": 1, "country": 1})
for student in students:
    print(student)

# 查找 name = David 的項目
names = db.students.find({"name": "David"})
for name in names:
    print(name)

ages = db.students.find({"age": {"$gt": 30}}, {"_id": 0, "name": 1, "age": 1})
for age in ages:
    print(age)

印出結果;分隔線是用來加強可讀性的,非實際印出:

--- students ---
{'name': 'Asabeneh', 'country': 'Finland'}
{'name': 'David', 'country': 'UK'}
{'name': 'John', 'country': 'Sweden'}
{'name': 'Sami', 'country': 'Finland'}

--- names ---
{'_id': ObjectId('63465741861a2ea6862cb7ef'), 'name': 'David', 'country': 'UK', 'city': 
'London', 'age': 34}

--- ages ---
{'name': 'Asabeneh', 'age': 250}
{'name': 'David', 'age': 34}

限制查詢回傳數

使用 limit() 方法,接在 find() 方法後:

first_two_students = db.students.find({}, {"_id": 0, "name": 1, "country": 1}).limit(2)

for student in first_two_students:
    print(student)

""" 印出結果
{'name': 'Asabeneh', 'country': 'Finland'}
{'name': 'David', 'country': 'UK'}
"""

查詢回傳排序

使用 sort(key_or_list, direction) 方法,接在 find() 方法後:

  • key 是排序要依據的欄位名稱。
  • direction 如果是 1 會是升冪排序,-1 則是降冪排序。
query = {
    "_id": 0,
    "name": 1,
    "country": 1,
    "age": 1
}

students = db.students.find({}, query).sort("age", 1)
for student in students:
    print(student)

""" 印出結果
{'name': 'Sami', 'country': 'Finland', 'age': 25}
{'name': 'John', 'country': 'Sweden', 'age': 28}
{'name': 'David', 'country': 'UK', 'age': 34}
{'name': 'Asabeneh', 'country': 'Finland', 'age': 250}
"""

更新資料

使用 update_one(filter, new_values) 方法來更新目前 collection 中有的條目:

這個方法會搭配 $set 這個 operator。

query = {"age": 250}

new_value = {"$set":{"age": 38}}

db.students.update_one(query, new_value)
for student in db.students.find():
    print(student)

""" 印出結果
{'_id': ObjectId('634651ae7d83d79be86e9603'), 'name': 'Asabeneh', 'country': 'Finland', 
'city': 'Helsinki', 'age': 38}
{'_id': ObjectId('63465741861a2ea6862cb7ef'), 'name': 'David', 'country': 'UK', 'city': 
'London', 'age': 34}
{'_id': ObjectId('63465741861a2ea6862cb7f0'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28}
{'_id': ObjectId('63465741861a2ea6862cb7f1'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}
"""

如果要更新多筆資料的話,可以使用 update_many(filter, update) 方法。

刪除資料

使用 delete_one(filter) 刪除 collection 中符合條件的第一個項目:

query = {"name": "John"}

db.students.delete_one(query)
for student in db.students.find():
    print(student)

"""印出結果
{'_id': ObjectId('634651ae7d83d79be86e9603'), 'name': 'Asabeneh', 'country': 'Finland', 
'city': 'Helsinki', 'age': 38}
{'_id': ObjectId('63465741861a2ea6862cb7ef'), 'name': 'David', 'country': 'UK', 'city': 
'London', 'age': 34}
{'_id': ObjectId('63465741861a2ea6862cb7f1'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}
"""

如果要刪除多筆資料的話,可以使用 delete_many(filter) 方法。如果給 filter 參數是空物件 {}的話,會刪除 collection 中所有資料。

刪除資料庫

這是一個危險的操作

使用 drop() 方法,會把該資料庫刪除,以這篇文章的例子來看,thirty_days_of_python 連同裡面的 collection students 都會被刪除:

db.students.drop()

上一篇
【Day 27】Python for Web
下一篇
【Day 29】打造一個 API
系列文
從前端角度看30天學Python30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言